#include "puts_gets.h"


int recvn(int sockfd, void *buf, long total){
        char *p = (char *)buf;
            long cursize = 0;
            while(cursize < total){
                        ssize_t sret = recv(sockfd,p+cursize,total-cursize,0);
                        if(sret == 0){
                    return 1;
                        }
                                cursize += sret;           
            }
                return 0;               
}

//例：传参netdisk/usr1/file 调用此函数 返回file1 
char *getfilename(char * path){
    int front = 0 ;
    int rear = strlen(path);
    char *curr = path;
    for(int i =0 ;i < strlen(path);i++){
        if(curr[i] == '/'){
            front = i;
        }
    }
    char* filename = (char*)malloc(sizeof(char) * 1024);
    strncpy(filename,&path[front],strlen(path)-front);
    return filename;
    }


//用户输入 gets /usr1/file1(网盘的虚拟路径) /home/54th/netdisk/user1/file1(客户端的真实路径)
//调用gets()参数时传入的是客户端的真实路径
//下载服务器传来的文件到真实路径里 

int getsfiles(char *realpath,int sockfd){
    //gets 下载 接收从服务端传来的文件
    train_t train;
    train.flag = 1;
    //新建火车 保存到火车   
    char filename[1024] = {0};
    //先收发来的文件名
    recvn(sockfd,&train.flag,sizeof(int));
    recvn(sockfd,&train.length,sizeof(train.length));
    recvn(sockfd,train.data,train.length);
    memcpy(filename,train.data,train.length);
    printf("filename:%s\n",filename);
    //再收发来的文件总长度
    off_t filesize;
    recvn(sockfd,&train.flag,sizeof(int));
    recvn(sockfd,&train.length,sizeof(train.length));
    recvn(sockfd,train.data,train.length);
    memcpy(&filesize,train.data,train.length);
    printf("filesize = %ld\n", filesize);
    printf("client is going to wait file...\n");
    int fd_exist = open(realpath,O_RDWR);

    //此时存在一个文件
    //发送断点续传火车
    off_t offset = 0;
    if(fd_exist != -1){
    struct stat statbuf;
    //设置偏移量
    fstat(fd_exist,&statbuf);
    train.flag = 1;
    train.length = sizeof(off_t);
    //把存在的文件长度放进小火车车厢
    memcpy(train.data,&statbuf.st_size,train.length);
    printf("exist filesize = %ld\n",statbuf.st_size);
    offset += statbuf.st_size;//若已存在文件就增加偏移量
    printf("offset has changed!=%ld\n",offset);
    send(sockfd,&train,sizeof(train.length)+train.length+sizeof(int),MSG_NOSIGNAL);
    off_t filesize;
    memcpy(&filesize,train.data,train.length);
    printf("request train data = %ld\n",filesize);
    }
    //不存在文件 发送一个flag为0的火车表示不存在
    else{
        train.flag = 0;
        send(sockfd,&train,sizeof(train.length)+train.length+sizeof(int),MSG_NOSIGNAL);
    }

    int fd = open(realpath,O_CREAT|O_RDWR|O_TRUNC,0666);
    //接下来的函数用来接收文件
    off_t cursize = offset;
    off_t lastsize = 0;
    off_t slice = filesize/100000;
    lseek(fd,offset,0);

    while(1){
        //接收火车的flag
        recvn(sockfd,&train.flag,sizeof(int));
        //接收文件长度
        recvn(sockfd,&train.length,sizeof(train.length));
        if(train.length < 1000){
            printf("train length = %d\n",train.length);
        }
        if(train.length == 0 ){
            break;
        }
       cursize += train.length;
       recvn(sockfd,&train.data,train.length);
       //接收文件数据
       write(fd,&train.data,train.length);
       if(cursize - lastsize >slice ){
           printf("%5.2lf%%\r", cursize*100.0/filesize);
           fflush(stdout);
           lastsize = cursize;
       }

    }
    printf("100.00\n");
    printf("client has recved from client!\n");
    close(fd);
    return 0;
}

//用户输入 puts /home/54th/usr1/file1(客户端文件的真实路径) /user1/file1(网盘的虚拟路径)
//调用puts()参数时传入的是客户端的真实路径
//上传用户端真实路径下的文件到服务器 
int putsfiles(char*realpath ,int sockfd,char *newfilename){
    train_t train;
    train.flag = 1;
    int fd = open(realpath,O_RDWR);
    //先发送自己的文件名
    train.length = strlen(newfilename);
    memcpy(train.data,newfilename,train.length);
    send(sockfd,&train,sizeof(train.length)+train.length+sizeof(int),MSG_NOSIGNAL);
    //再发送自己的文件
    struct stat statbuf;
    fstat(fd,&statbuf);
    train.length = sizeof(off_t);
    memcpy(train.data,&statbuf.st_size,train.length);
    printf("filesize :%ld\n",statbuf.st_size);
    send(sockfd,&train,sizeof(train.length)+train.length+sizeof(int),MSG_NOSIGNAL);
    printf("client is going to translate file to server !\n");
    if(statbuf.st_size>=104857600){
        printf("this is a bigfile , will use mmap to transfile!\n");
        char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        ERROR_CHECK(p,MAP_FAILED,"mmap"); 
        off_t cursize = 0;
        while(1){
            //若传输完毕
            if(cursize >= statbuf.st_size){
             break;
            }
            if(statbuf.st_size - cursize > 1000){
                train.length = 1000;
            }
            else{
                train.length = statbuf.st_size - cursize;
            }
            send(sockfd,&train.flag,sizeof(train.flag),MSG_NOSIGNAL);
            //发送小火车长度
            send(sockfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
            send(sockfd,p+cursize,train.length,MSG_NOSIGNAL);
            //发送文件内容
          cursize += train.length;
          //改cursize长度
        }
        munmap(p,statbuf.st_size);
        close(fd);
        printf("bigfile has been translatend!\n");
        return 0;
    }
    else{
        //小文件
    while(1){
        train.flag = 1;
         //读文件数据1000个字节到火车data
        ssize_t sret = read(fd,train.data,sizeof(train.data));
        //获得火车长度
        train.length = sret;
    ssize_t sret1 = send(sockfd,&train,sizeof(train),MSG_NOSIGNAL);
        if(sret == 0 || sret1 == -1){
            break;
        }
        usleep(1000);
     }

    printf("file has been translated to server!\n");
    close(fd);
    
}
}
